<template>
  <div style="height: 100%;width:100%;">
    <div id="map" style="height: 100%;width:100%;"></div>
    <!-- 设备信息弹窗 -->
    <div class="ol-popup" ref="overlayPopup">
      <div class="eachItem">{{featurePopupData}}</div>
    </div>
  </div>
</template>
 
<script>
import ol from 'openlayers';
import axios from "axios";
import pointData from "./pointData"
 
// 聚合图标缓存，避免重复创建
var styleCache = [];
export default {
  name: "pgisMapOL",
  data() {
    return {
      map: null, // 地图对象
      vectorSource: null, // 点位数据源
      vectorTile: null, // 点位数据图层
      timer: null,
      curZoom: 12,
      resolutionChange: false,

      selectSingleClick: null,  // 点击选择的对象
      overlayPopup: null, // popup对象
      featurePopupData: null,  // popup的数据
      featureDataTxt: "",
    };
  },
  mounted() {
    this.initMap();
  },
  methods:{
    initMap() {
      this.map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          }),
          // new ol.layer.Tile({
          //   source: new ol.source.XYZ({
          //     wrapX: false, // 是否水平包装世界。设为时false，只会渲染一个世界
          //     url: "http://192.168.33.196:8088/roadmap/{z}/{x}/{y}.png",
          //   }),
          // })
        ],
        controls: ol.control.defaults({}).extend([
          new ol.control.MousePosition({
            coordinateFormat: ol.coordinate.createStringXY(5), //保留5位小数
            projection: "EPSG:4326"
          }),
        ]),
        target: "map",
        view: new ol.View({
          zoom: 12,
          minZoom: 5,
          maxZoom: 15,
          center: [113.05642461656782, 23.6758880181949], //[116.63178, 23.64661],
          projection: "EPSG:4326", // EPSG:4326
        }),
      });
      this.curZoom = this.map.getView().getZoom().toFixed(0)
      this.map.getView().on("change:resolution", () =>{   
        this.resolutionChange = true             
        if (this.timer !== null) {
            clearTimeout(this.timer);
        }
        this.timer = setTimeout(() => {
            this.vectorSource.clear();
            this.curZoom = this.map.getView().getZoom().toFixed(0);
            this.resolutionChange = false
        }, 35);
      })
      this.addPointLayer()  // 添加设备图层
      // this.featureClick()  // 点击要素方法 
      this.map.on('click', evt => {this.clickMap(evt)});      //单击事件
    },
    // 地图点位数据加载
    addPointLayer() {
      this.vectorSource = new ol.source.Vector({
          loader: (extent, resolution, projection) =>{
              //控制缩放结束前不发送请求
              if (this.resolutionChange)
              return false;
              // 此处loader自动请求后台数据，由于需要模拟数据，因为把请求注释。接口返回的实际，用pointData进行模拟
              // axios({
              //   method: "post",
              //   timeout: 1000,
              //   url: "http://192.168.30.10:8907/vector/tile",
              //   // params表示当前视野范围，把当前视野作为参数，传递给后台进行查询
              //   params: {
              //     minX: extent[0],
              //     minY: extent[1],
              //     maxX: extent[2],
              //     maxY: extent[3]
              //   },
              // }).then((res) => {
              //   console.log(res)
              // })

              // 接口返回成功以后，里面调用的方法=======start=======
              var z = Number(this.map.getView().getZoom().toFixed(0))
              let rsp = pointData[z]; 
              if (z == this.curZoom) {
                  var count = rsp.data.length
                  if(!count) {
                      return false
                  }
                  var features = new Array(count)                  
                  for (var i = 0; i < count; ++i) {
                      var coordinates = [Number(rsp.data[i].gpsX), Number(rsp.data[i].gpsY)]
                      let featureAttr = Object.assign({
                          geometry: new ol.geom.Point(coordinates),
                          data: rsp.data[i]
                      })
                      features[i] = new ol.Feature(featureAttr);
                      features[i].setId(featureAttr.data.channel_ids)
                  }
                  this.vectorSource.addFeatures(features);
              }
            // 接口返回成功以后，里面调用的方法=======end=======
          },
          strategy: ol.loadingstrategy.tile(
              ol.tilegrid.createXYZ({
                  tileSize: 512,
              })
          )
      });
      this.vectorTile = new ol.layer.Vector({                             
        // 此处预留按照图层名称进行渲染的入口，先写死图层名称为"layerName"，   
        style: feature => this.setClusterStyle(feature),   
        source: this.vectorSource,
        zIndex: 100,
      })
      this.map.addLayer(this.vectorTile) 
    },
    // 设置聚合数据源样式
    setClusterStyle(feature) {
      let featureData = feature.get('data')
      if(JSON.stringify(featureData) == "{}"){
          return false
      }
      let count = featureData.count || 1          
      // 1-15层用count为1都显示聚合图标，16层及后面就显示正常图标
      if (styleCache[count] == undefined) {
          styleCache[count] = new ol.style.Style({
              image: new ol.style.Circle({
                  radius: 16,
                  stroke: new ol.style.Stroke({
                      color: '#fff',
                  }),
                  fill: new ol.style.Fill({
                      color: 'rgba(97,134,236,0.9)'
                  })
              }),
              text: new ol.style.Text({
                  font: '12px sans-serif',
                  text: ''+ count,
                  fill: new ol.style.Fill({
                      color: '#fff',
                  }),
              })
          })
      }                               
      return styleCache[count] 
    },
    //点击事件
    clickMap(evt) {
        var coordinate = evt.coordinate;
        let featureMouseOver = this.map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
            return feature;
        })
        if (!featureMouseOver){
            this.closeVideoPopup()  // 关闭已打开的详情popup
              return 
        }
        let fData = featureMouseOver.get("data")    // 获取得到聚合点的数据
        if(!fData) {
            return false
        }
        this.showFeature(fData, coordinate) 
    },
    // 给页面的要素添加点击事件
    featureClick() {
      this.selectSingleClick = new ol.interaction.Select({
          style: new ol.style.Style({             
              image: new ol.style.Circle({
                  radius: 15,
                  fill: new ol.style.Fill({
                      color: "rgba(70,220,198,0.5)" // 直接隐藏交互样式
                  })
              })
          })
      });
      this.map.addInteraction(this.selectSingleClick);
      this.selectSingleClick.on('select', e =>{
          var featuresAry=e.selected;               
          if (featuresAry.length>0){
              let featureList=featuresAry[0];
              let coordinate = ol.extent.getCenter(featureList.getGeometry().getExtent());    // 点击的点经纬度
              // 至此得出聚合图层的要素列表
              let featureData=featureList.getProperties().data;
              this.showFeature(featureData, coordinate)                             
          } else {
              this.closeVideoPopup()  // 关闭已打开的详情popup
          }
      })
    },
    showFeature(featureData, coordinate) {
      let overlayPopup = this.$refs.overlayPopup;
      this.featurePopupData = featureData
      if (!this.overlayPopup) {
          this.overlayPopup = new ol.Overlay({
              element: overlayPopup,
              offset: [10, 0],
          });
          overlayPopup.style.display = 'block';
          this.map.addOverlay(this.overlayPopup);
      } else {
          overlayPopup.style.display = 'block';
          this.overlayPopup.setOffset([10, 0]); // 设置偏移量
          this.overlayPopup.setElement(overlayPopup);
      }
      this.overlayPopup.setPosition(coordinate);
    },
    //关闭overlayPopup
    closeVideoPopup() {
        let overlayPopup = this.$refs.overlayPopup;
        if(overlayPopup) {
            overlayPopup.style.display = 'none';
        }
    },
  }
};
</script>
<style lang="less" scoped>
.ol-popup {
    position: relative;
    padding: 12px 15px;
    border-radius: 10px;
    display: none;
    background-color: #fff;
    color: #666;
    min-width: 384px;
    box-shadow: 0px 0px 10px #ccc;
    .eachItem {
        padding: 4px 0px;
        color: #111;
    }
}
</style>